package db

import (
	"bytes"
	"encoding/hex"
	"fmt"
	"sort"
	"testing"

	"github.com/stretchr/testify/assert"
)

// BaseTestDBIteratorAllKey 基础迭代测试所有key
func BaseTestDBIteratorAllKey(t *testing.T, db Database) {
	var datas = [][]byte{
		[]byte("aa0"), []byte("aa1"), []byte("bb0"), []byte("bb1"), []byte("cc0"), []byte("cc1"),
	}
	for _, v := range datas {
		db.Set(v, v)
	}
	//一次遍历
	it := db.NewIteratorWithRange(nil, nil)
	i := 0
	for it.First(); it.Valid(); it.Next() {
		assert.Equal(t, it.Key(), datas[i])
		db.Delete(it.Key())
		i++
		if i == 2 {
			break
		}
	}
	it.Release()
	//从第3个开始遍历
	it = db.NewIteratorWithRange([]byte("aa1"), nil)
	i = 2
	for it.First(); it.Valid(); it.Next() {
		assert.Equal(t, it.Key(), datas[i])
		db.Delete(it.Key())
		i++
		if i == 4 {
			break
		}
	}
	it.Release()
	//从第5个开始遍历
	it = db.NewIteratorWithRange([]byte("bb1"), nil)
	i = 4
	for it.First(); it.Valid(); it.Next() {
		assert.Equal(t, it.Key(), datas[i])
		db.Delete(it.Key())
		i++
		if i == 6 {
			break
		}
	}
	it.Release()
}

// BaseTestDBList 迭代测试
func BaseTestDBList(t *testing.T, db Database) {
	t.Log("test Set")

	kvs := genDefaultKV()
	for _, kv := range kvs {
		db.Set(kv.key, kv.value)
	}

	t.Log("for test exist pre key, this is my_key/_3")
	keys, values, err := db.NewList().ListRange([]byte("my_key/1"), []byte("my_key/4"), 1, OptionReverse|OptionWithKey|OptionWithValue)
	assert.NoError(t, err)
	assert.Equal(t, len(values), 1)
	assert.Equal(t, keys[0], []byte("my_key/3"))

	t.Log("for test exist pre key, this is my_key/_2")
	keys, values, err = db.NewList().ListRange([]byte("my_key/1"), []byte("my_key/3"), 1, OptionReverse|OptionWithKey|OptionWithValue)
	assert.NoError(t, err)
	assert.Equal(t, len(values), 1)
	assert.Equal(t, keys[0], []byte("my_key/2"))

	//test list:
	_, values, err = db.NewList().ListRange(nil, nil, -1, OptionWithValue)
	assert.NoError(t, err)
	assert.Equal(t, len(values), len(kvs))
	for _, v := range values {
		t.Log("list0", string(v))
	}

	t.Log("test Prefix")
	_, list, err := db.NewList().ListPrefix(nil, -1, OptionWithValue)
	assert.NoError(t, err)
	assert.Equal(t, len(list), len(kvs))
	for _, v := range list {
		t.Log("list:", string(v))
	}
	assert.Equal(t, values, list)

	t.Log("test Iterator list reverse with key and value")
	keys, values, err = db.NewList().ListPrefix([]byte("my"), -1, OptionReverse|OptionWithKey|OptionWithValue)
	assert.Equal(t, keys, values)
	assert.Equal(t, len(keys), 5)
	assert.Equal(t, keys[0], []byte("my_key/3"))
	assert.Equal(t, keys[4], []byte("my"))

	t.Log("test Iterator list OptionWithValue value")
	_, values, err = db.NewList().ListPrefix([]byte("my_key/3"), -1, OptionWithValue)
	assert.NoError(t, err)
	assert.Equal(t, len(values), 1)
	assert.Equal(t, values[0], []byte("my_key/3"))
}

// BaseTestDBBoundary 测试边界
func BaseTestDBBoundary(t *testing.T, db Database) {
	a, _ := hex.DecodeString("0f")
	c, _ := hex.DecodeString("0fff")
	b, _ := hex.DecodeString("ff")
	d, _ := hex.DecodeString("ffff")
	db.Set(a, []byte("0x0f"))
	db.Set(c, []byte("0x0fff"))
	db.Set(b, []byte("0xff"))
	db.Set(d, []byte("0xffff"))

	var v []byte
	_ = v
	it := db.NewList()

	// f为prefix
	t.Log("ListPrefix")
	_, values, err := it.ListPrefix(a, 2, OptionWithValue)
	assert.NoError(t, err)
	assert.Equal(t, values, [][]byte{[]byte("0x0f"), []byte("0x0fff")})

	t.Log("ListPrefix OptionReverse")
	_, values, err = it.ListPrefix(a, 100, OptionWithValue|OptionReverse)
	assert.NoError(t, err)
	assert.Equal(t, values, [][]byte{[]byte("0x0fff"), []byte("0x0f")})

	t.Log("ListRange 0")
	_, values, err = it.ListRange(a, nil, 100, OptionWithValue)
	assert.Equal(t, values, [][]byte{[]byte("0x0f"), []byte("0x0fff"), []byte("0xff"), []byte("0xffff")})

	t.Log("ListRange 1")
	_, values, err = it.ListRange(a, nil, 100, OptionWithValue|OptionReverse)
	assert.Equal(t, values, [][]byte{[]byte("0xffff"), []byte("0xff"), []byte("0x0fff"), []byte("0x0f")})

	// ff为prefix
	t.Log("PrefixScan")
	_, values, err = it.ListPrefix(b, -1, OptionWithValue)
	assert.NoError(t, err)
	assert.Equal(t, values, [][]byte{[]byte("0xff"), []byte("0xffff")})

	t.Log("PrefixScan")
	_, values, err = it.ListPrefix(b, 2, OptionWithValue)
	assert.Equal(t, values, [][]byte{[]byte("0xff"), []byte("0xffff")})

	t.Log("PrefixScan OptionReverse")
	_, values, err = it.ListPrefix(b, 100, OptionWithValue|OptionReverse)
	assert.Equal(t, values, [][]byte{[]byte("0xffff"), []byte("0xff")})

	t.Log("ListRange")
	_, values, err = it.ListRange(b, nil, 100, OptionWithValue)
	assert.Equal(t, values, [][]byte{[]byte("0xff"), []byte("0xffff")})

	t.Log("ListRange OptionReverse")
	_, values, err = it.ListRange(b, d, 100, OptionWithValue|OptionReverse)
	assert.Equal(t, values, [][]byte{[]byte("0xff")})
}

// BaseTestDBIteratorDel 迭代删除测试
func BaseTestDBIteratorDel(t *testing.T, db Database) {
	for i := 0; i < 1000; i++ {
		k := []byte(fmt.Sprintf("my_key/%010d", i))
		v := []byte(fmt.Sprintf("my_value/%010d", i))
		db.Set(k, v)
	}

	prefix := []byte("my")
	it := db.NewIteratorWithPrefix(prefix)
	defer it.Release()
	for it.First(); it.Valid(); it.Next() {
		t.Log(string(it.Key()), "*********", string(it.Value()))
		batch := db.NewBatch(true)
		batch.Delete(it.Key())
		batch.Write()
	}
}

// BaseTestDBIteratorResult 返回值测试
func BaseTestDBIteratorResult(t *testing.T, db Database) {
	t.Log("test Set")
	kvs := genUnsameDefaultKV()
	for _, kv := range kvs {
		db.Set(kv.key, kv.value)
	}

	//test list:
	// 正向遍历
	keys, values, err := db.NewList().ListPrefix([]byte("my_key"), -1, OptionWithKey|OptionWithValue)
	assert.NoError(t, err)
	assert.Equal(t, keys, [][]byte{[]byte("my_key/1"), []byte("my_key/2"), []byte("my_key/3")})
	assert.Equal(t, values, [][]byte{[]byte("my_key/1_value"), []byte("my_key/2_value"), []byte("my_key/3_value")})

	// 反向遍历
	keys, values, err = db.NewList().ListPrefix([]byte("my"), 4, OptionReverse|OptionWithKey|OptionWithValue)
	assert.NoError(t, err)
	assert.Equal(t, keys, [][]byte{[]byte("my_key/3"), []byte("my_key/2"), []byte("my_key/1"), []byte("my_")})
	assert.Equal(t, values, [][]byte{[]byte("my_key/3_value"), []byte("my_key/2_value"), []byte("my_key/1_value"), []byte("my__value")})

	// prefix count
	count := db.NewList().PrefixCount([]byte("my"))
	assert.Equal(t, count, int64(5))
}

// KV ...
type KV struct {
	key   []byte
	value []byte
}

func genUnsameDefaultKV() []*KV {
	b, _ := hex.DecodeString("ff")
	kvs := []*KV{
		{[]byte("aaaaaa/1"), []byte("aaaaaa/1_value")},
		{[]byte("my"), []byte("my_value")},
		{[]byte("my_"), []byte("my__value")},
		{[]byte("my_key/1"), []byte("my_key/1_value")},
		{[]byte("my_key/2"), []byte("my_key/2_value")},
		{[]byte("my_key/3"), []byte("my_key/3_value")},
		{[]byte("zzzzzz/1"), []byte("zzzzzz/1_value")},
		{b, []byte("0xff_value")},
	}
	sort.Slice(kvs, func(i, j int) bool {
		res := bytes.Compare(kvs[i].key, kvs[j].key)
		if res == 0 || res == -1 {
			return false
		}
		return true
	})
	return kvs
}

func genDefaultKV() []*KV {
	b, _ := hex.DecodeString("ff")
	kvs := []*KV{
		{[]byte("aaaaaa/1"), []byte("aaaaaa/1")},
		{[]byte("my"), []byte("my")},
		{[]byte("my_"), []byte("my_")},
		{[]byte("my_key/1"), []byte("my_key/1")},
		{[]byte("my_key/2"), []byte("my_key/2")},
		{[]byte("my_key/3"), []byte("my_key/3")},
		{[]byte("zzzzzz/1"), []byte("zzzzzz/1")},
		{b, []byte("0xff")},
	}
	sort.Slice(kvs, func(i, j int) bool {
		res := bytes.Compare(kvs[i].key, kvs[j].key)
		if res == 0 || res == -1 {
			return false
		}
		return true
	})
	return kvs
}
